﻿using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;

namespace EfInfra.Ext
{
    /// <summary>
    /// ModelBuilder扩展，在table映射时，通过传递方法，改变映射内容
    /// </summary>
    public static class ModelBuilderExt
    {
        public static ModelBuilder TableMappingTo(this ModelBuilder modelBuilder,
    Func<IMutableEntityType, bool> verifyingEntityType,
    Func<string, string> processString)
        {
            var model = modelBuilder.Model;
            foreach (var entityType in model.GetEntityTypes())
            {
                // 校验
                if (!verifyingEntityType(entityType))
                {
                    continue;
                }

                var entityBuilder = modelBuilder.Entity(entityType.ClrType);

                // 表名处理
                {
                    // 注释中的名字
                    var tblAnnotion=entityBuilder.Metadata.FindAnnotation(RelationalAnnotationNames.TableName);
                    var tableName = entityBuilder.Metadata.GetTableName();

                    if (tblAnnotion is not null)
                    {
                        tableName = tblAnnotion!.Value!.ToString();
                    }
                    else
                    {
                        tableName = entityType.ClrType.Name;
                        tableName = processString.Invoke(tableName!);
                    }

                    entityBuilder.Metadata.SetTableName(tableName);
                }

                // 列名处理
                {
                    var annotation = default(IAnnotation);
                    var columnName = string.Empty;
                    foreach (var property in entityType.GetProperties())
                    {
                        columnName = property.GetColumnName();
                        annotation = property.FindAnnotation(RelationalAnnotationNames.ColumnName);
                        if (annotation != null)
                        {
                            columnName = annotation.Value!.ToString();
                        }
                        // 设置默认长度
                        // property.SetMaxLength(20);

                        // 设置列名
                        property.SetColumnName(
                            processString.Invoke(columnName!)
                        );

                        // 与上句功能相同
                        modelBuilder.Entity(entityType.Name)
                        .Property(property.Name)
                        .HasColumnName(processString.Invoke(columnName!));
                    }
                }

                // 主键处理
                {
                    var keyName = string.Empty;
                    var keys = entityBuilder.Metadata.GetKeys();
                    foreach (var key in keys)
                    {
                        keyName = key.GetName();
                        if (string.IsNullOrEmpty(keyName))
                        {
                            keyName = key.GetDefaultName();
                        }
                        keyName = processString.Invoke(keyName!);
                        key.SetName(keyName);
                    }
                }

                // 外键处理
                {
                    var keyName = string.Empty;
                    var keys = entityBuilder.Metadata.GetForeignKeys();
                    foreach (var key in keys)
                    {
                        keyName = key.GetConstraintName();
                        if (string.IsNullOrEmpty(keyName))
                        {
                            keyName = key.GetDefaultName();
                        }
                        keyName = processString.Invoke(keyName!);
                        key.SetConstraintName(keyName);
                    }
                }

                // 索引处理
                {
                    var keyName = string.Empty;
                    var keys = entityBuilder.Metadata.GetIndexes();
                    foreach (var key in keys)
                    {
                        keyName = key.GetDatabaseName();
                        if (string.IsNullOrEmpty(keyName))
                        {
                            keyName = key.GetDefaultDatabaseName();
                        }
                        keyName = processString.Invoke(keyName!);
                        key.SetDatabaseName(keyName);
                    }
                }


            }

            return modelBuilder;
        }
    }
}
